<html>
 <head>
  <meta charset="utf-8"/>
  <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"/>
  <title>
   淘宝内部分享：MySQL &amp; MariaDB性能优化  | 数螺 | NAUT IDEA
  </title>
  <link href="http://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" rel="stylesheet"/>
  <link href="http://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
  <style type="text/css">
   #xmain img {
                  max-width: 100%;
                  display: block;
                  margin-top: 10px;
                  margin-bottom: 10px;
                }

                #xmain p {
                    line-height:150%;
                    font-size: 16px;
                    margin-top: 20px;
                }

                #xmain h2 {
                    font-size: 24px;
                }

                #xmain h3 {
                    font-size: 20px;
                }

                #xmain h4 {
                    font-size: 18px;
                }


                .header {
	           background-color: #0099ff;
	           color: #ffffff;
	           margin-bottom: 20px;
	        }

	        .header p {
                  margin: 0px;
                  padding: 10px 0;
                  display: inline-block;  
                  vertical-align: middle;
                  font-size: 16px;
               }

               .header a {
                 color: white;
               }

              .header img {
                 height: 25px;
              }
  </style>
  <script src="http://cdn.bootcss.com/jquery/3.0.0/jquery.min.js">
  </script>
  <script src="http://nautstatic-10007657.file.myqcloud.com/static/css/readability.min.js" type="text/javascript">
  </script>
  <script type="text/javascript">
   $(document).ready(function() {
                 var loc = document.location;
                 var uri = {
                  spec: "http://dataunion.org/8791.html",
                  host: "http://dataunion.org",
                  prePath: "http://dataunion.org",
                  scheme: "http",
                  pathBase: "http://dataunion.org/"
                 };
    
                 var documentClone = document.cloneNode(true);
                 var article = new Readability(uri, documentClone).parse();
     
                 document.getElementById("xmain").innerHTML = article.content;
                });
  </script>
  <!-- 1466459341: Accept with keywords: (title(0.2):性能,社区,优化,数盟,淘宝, topn(0.233333333333):社区,队列,数盟,行业资讯,查找,内存,淘宝,分区,基础架构,文章,类型,参数,排序,数据,子系统,结构,备库,记录,性能,用户,问题,次数,算法,磁盘,优化,顺序,全表,节点,版本,时候).-->
 </head>
 <body onload="">
  <div class="header">
   <div class="container">
    <div class="row">
     <div class="col-xs-6 col-sm-6 text-left">
      <a href="/databee">
       <img src="http://nautidea-10007657.cos.myqcloud.com/logo_white.png"/>
      </a>
      <a href="/databee">
       <p>
        数螺
       </p>
      </a>
     </div>
     <div class="hidden-xs col-sm-6 text-right">
      <p>
       致力于数据科学的推广和知识传播
      </p>
     </div>
    </div>
   </div>
  </div>
  <div class="container text-center">
   <h1>
    淘宝内部分享：MySQL &amp; MariaDB性能优化
   </h1>
  </div>
  <div class="container" id="xmain">
   ﻿﻿
   <title>
    淘宝内部分享：MySQL &amp; MariaDB性能优化 | 数盟社区
   </title>
   <!-- All in One SEO Pack 2.2.7.6.2 by Michael Torbert of Semper Fi Web Design[32,78] -->
   <!-- /all in one seo pack -->
   <!--
<div align="center">
<a href="http://strata.oreilly.com.cn/hadoop-big-data-cn?cmp=mp-data-confreg-home-stcn16_dataunion_pc" target="_blank"><img src="http://dataunion.org/wp-content/uploads/2016/05/stratabj.jpg"/ ></a>
</div>
-->
   <header id="header-web">
    <div class="header-main">
     <hgroup class="logo">
      <h1>
       <a href="http://dataunion.org/" rel="home" title="数盟社区">
        <img src="http://dataunion.org/wp-content/themes/yzipi/images/logo.png"/>
       </a>
      </h1>
     </hgroup>
     <!--logo-->
     <nav class="header-nav">
      <ul class="menu" id="menu-%e4%b8%bb%e8%8f%9c%e5%8d%95">
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-has-children menu-item-71" id="menu-item-71">
        <a href="http://dataunion.org/category/events" title="events">
         活动
        </a>
        <ul class="sub-menu">
         <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-22457" id="menu-item-22457">
          <a href="http://dataunion.org/2016timeline">
           2016档期
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-22459" id="menu-item-22459">
          <a href="http://dataunion.org/category/parterc">
           合作会议
          </a>
         </li>
        </ul>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor menu-item-has-children menu-item-20869" id="menu-item-20869">
        <a href="http://dataunion.org/category/tech" title="articles">
         文章
        </a>
        <ul class="sub-menu">
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent menu-item-20867" id="menu-item-20867">
          <a href="http://dataunion.org/category/tech/base" title="base">
           基础架构
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-3302" id="menu-item-3302">
          <a href="http://dataunion.org/category/tech/ai" title="ai">
           人工智能
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-3303" id="menu-item-3303">
          <a href="http://dataunion.org/category/tech/analysis" title="analysis">
           数据分析
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-21920" id="menu-item-21920">
          <a href="http://dataunion.org/category/tech/dm">
           数据挖掘
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-3314" id="menu-item-3314">
          <a href="http://dataunion.org/category/tech/viz" title="viz">
           可视化
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-3305" id="menu-item-3305">
          <a href="http://dataunion.org/category/tech/devl" title="devl">
           编程语言
          </a>
         </li>
        </ul>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-has-children menu-item-20876" id="menu-item-20876">
        <a href="http://dataunion.org/category/industry">
         行业
        </a>
        <ul class="sub-menu">
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-16328" id="menu-item-16328">
          <a href="http://dataunion.org/category/industry/case" title="case">
           行业应用
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-2112" id="menu-item-2112">
          <a href="http://dataunion.org/category/industry/demo" title="demo">
           Demo展示
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-21562" id="menu-item-21562">
          <a href="http://dataunion.org/category/industry/news">
           行业资讯
          </a>
         </li>
        </ul>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-311" id="menu-item-311">
        <a href="http://dataunion.org/category/sources" title="sources">
         资源
        </a>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-20870" id="menu-item-20870">
        <a href="http://dataunion.org/category/books" title="book">
         图书
        </a>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-21363" id="menu-item-21363">
        <a href="http://dataunion.org/category/training">
         课程
        </a>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-has-children menu-item-21853" id="menu-item-21853">
        <a href="http://dataunion.org/category/jobs">
         职位
        </a>
        <ul class="sub-menu">
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-22050" id="menu-item-22050">
          <a href="http://dataunion.org/category/career">
           职业规划
          </a>
         </li>
        </ul>
       </li>
      </ul>
     </nav>
     <!--header-nav-->
    </div>
   </header>
   <!--header-web-->
   <div id="main">
    <div id="soutab">
     <form action="http://dataunion.org/" class="search" method="get">
     </form>
    </div>
    <div id="container">
     <nav id="mbx">
      当前位置：
      <a href="http://dataunion.org">
       首页
      </a>
      &gt;
      <a href="http://dataunion.org/category/tech">
       文章
      </a>
      &gt;
      <a href="http://dataunion.org/category/tech/base">
       基础架构
      </a>
      &gt;  正文
     </nav>
     <!--mbx-->
     <article class="content">
      <header align="centre" class="contenttitle">
       <div class="mscc">
        <h1 class="mscctitle">
         <a href="http://dataunion.org/8791.html">
          淘宝内部分享：MySQL &amp; MariaDB性能优化
         </a>
        </h1>
        <address class="msccaddress ">
         <em>
          1,969 次阅读 -
         </em>
         <a href="http://dataunion.org/category/tech/base" rel="category tag">
          基础架构
         </a>
        </address>
       </div>
      </header>
      <div class="content-text">
       <p>
       </p>
       <h2>
        MySQL·　5.7优化·Metadata Lock子系统的优化
       </h2>
       <div>
        <p>
         背景
        </p>
        <p>
         引入MDL锁的目的，最初是为了解决著名的bug#989，在MySQL 5.1及之前的版本，事务执行过程中并不维护涉及到的所有表的Metatdata 锁，极易出现复制中断，例如如下执行序列：
        </p>
        <blockquote>
         <p>
          Session 1: BEGIN;
          <br/>
          Session 1: INSERT INTO t1 VALUES (1);
          <br/>
          Session 2: Drop table t1; ——–SQL写入BINLOG
          <br/>
          Session 1: COMMIT; —–事务写入BINLOG
         </p>
        </blockquote>
        <p>
         在备库重放 binlog时，会先执行DROP TABLE，再INSERT数据，从而导致复制中断。
        </p>
        <blockquote>
         <p>
          相关阅读：
          <a href="http://dataunion.org/?p=8336">
           淘宝内部分享：怎么跳出MySQL的10个大坑
          </a>
         </p>
        </blockquote>
        <p>
         在MySQL 5.5版本里，引入了MDL, 在事务过程中涉及到的所有表的MDL锁，直到事务结束才释放。这意味着上述序列的DROP TABLE 操作将被Session 1阻塞住直到其提交。
        </p>
        <p>
         不过用过5.5的人都知道，MDL实在是个让人讨厌的东西，相信不少人肯定遇到过在使用mysqldump做逻辑备份时，由于需要执行FLUSH TABLES WITH READ LOCK (以下用FTWRL缩写代替)来获取全局GLOBAL的MDL锁，因此经常可以看到“wait for global read lock”之类的信息。如果备库存在大查询，或者复制线程正在执行比较漫长的DDL，并且FTWRL被block住，那么随后的QUERY都会被block住，导致业务不可用引发故障。
        </p>
        <p>
         为了解决这个问题，Facebook为MySQL增加新的接口替换掉FTWRL 只创建一个read view ，并返回与read view一致的binlog位点；另外Percona Server也实现了一种类似的办法来绕过FTWRL，具体点击
         <a href="http://www.percona.com/doc/percona-server/5.6/management/backup_locks.html">
          文档连接
         </a>
         以及
         <a href="http://www.mysqlperformanceblog.com/2014/03/11/introducing-backup-locks-percona-server-2/">
          percona的博客
         </a>
         ，不展开阐述。
        </p>
        <p>
         MDL解决了
         <a href="http://bugs.mysql.com/bug.php?id=989">
          bug#989
         </a>
         ，却引入了一个新的热点，所有的MDL锁对象被维护在一个hash对象中；对于热点，最正常的想法当然是对其进行分区来分散热点，不过这也是Facebook的大神Mark Callaghan在report了
         <a href="http://bugs.mysql.com/bug.php?id=66473">
          bug#66473
         </a>
         后才加入的，当时Mark观察到MDL_map::mutex的锁竞争非常高，进而推动官方改变。因此在MySQL 5.6.8及之后的版本中，引入了新参数metadata_locks_hash_instances来控制对mdl hash的分区数(
         <a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.6/revision/4350">
          Rev:4350
         </a>
         )；
        </p>
        <p>
         不过故事还没结束，后面的测试又发现哈希函数有问题，somedb. someprefix1 … .somedb .someprefix8 的hash key值相同，都被hash到同一个桶下面了，相当于hash分区没生效。这属于hash算法的问题，喜欢考古的同学可以阅读下bug#66473后面Dmitry Lenev的分析。
        </p>
        <p>
         Mark进一步的测试发现Innodb的hash计算算法比my_hash_sort_bin要更高效， Oracle的开发人员重开了个
         <a href="http://bugs.mysql.com/bug.php?id=68487">
          bug#68487
         </a>
         来跟踪该问题，并在MySQL5.6.15对hash key计算函数进行优化，包括fix 上面说的hash计算问题(
         <a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.6/revision/5459">
          Rev:5459
         </a>
         )，使用MurmurHash3算法来计算mdl key的hash值。
        </p>
        <p>
         <b>
          MySQL 5.7 对MDL锁的优化
         </b>
        </p>
        <p>
         在MySQL 5.7里对MDL子系统做了更为彻底的优化。主要从以下几点出发：
        </p>
        <p>
         <b>
          第一，尽管对MDL HASH进行了分区，但由于是以表名+库名的方式作为key值进行分区，如果查询或者DML都集中在同一张表上，就会hash到相同的分区，引起明显的MDL HASH上的锁竞争。
         </b>
        </p>
        <p>
         针对这一点，引入了LOCK-FREE的HASH来存储MDL_lock，LF_HASH无锁算法基于论文”Split-Ordered Lists: Lock-Free Extensible Hash Tables”，实现还比较复杂。 注：实际上LF_HASH很早就被应用于Performance Schema，算是比较成熟的代码模块。由于引入了LF_HASH，MDL HASH分区特性自然直接被废除了 。对应
         <a href="http://dev.mysql.com/worklog/task/?id=7305">
          WL#7305
         </a>
         ， PATCH(
         <a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/7249">
          Rev:7249
         </a>
         )
        </p>
        <p>
         <b>
          第二，从广泛使用的实际场景来看，DML/SELECT相比DDL等高级别MDL锁类型，是更为普遍的，因此可以针对性的降低DML和SELECT操作的MDL开销。
         </b>
        </p>
        <p>
         为了实现对DML/SELECT的快速加锁，使用了类似LOCK-WORD的加锁方式，称之为FAST-PATH，如果FAST-PATH加锁失败，则走SLOW-PATH来进行加锁。
        </p>
        <p>
         每个MDL锁对象（MDL_lock）都维持了一个long long类型的状态值来标示当前的加锁状态，变量名为MDL_lock::m_fast_path_state 举个简单的例子：（初始在sbtest1表上对应MDL_lock::m_fast_path_state值为0）
        </p>
        <blockquote>
         <p>
          Session 1: BEGIN;
          <br/>
          Session 1: SELECT * FROM sbtest1 WHERE id =1; //m_fast_path_state = 1048576, MDL ticket 不加MDL_lock::m_granted队列
          <br/>
          Session 2: BEGIN;
          <br/>
          Session 2: SELECT * FROM sbtest1 WHERE id =2; //m_fast_path_state=1048576+1048576=2097152，同上，走FAST PATH
          <br/>
          Session 3: ALTER TABLE sbtest1 ENGINE = INNODB; //DDL请求加的MDL_SHARED_UPGRADABLE类型锁被视为unobtrusive lock，可以认为这个是比上述SQL的MDL锁级别更高的锁，并且不相容，因此被强制走slow path。而slow path是需要加MDL_lock::m_rwlock的写锁。m_fast_path_state = m_fast_path_state | MDL_lock::HAS_SLOW_PATH | MDL_lock::HAS_OBTRUSIVE
          <br/>
          注:DDL还会获得库级别的意向排他MDL锁或者表级别的共享可升级锁，但为了表述方便，这里直接忽略了，只考虑涉及的同一个MDL_lock锁对象。
          <br/>
          Session 4: SELECT * FROM sbtest1 WHERE id =3; // 检查m_fast_path_state &amp;HAS_OBTRUSIVE，如果DDL还没跑完，就会走slow path。
         </p>
        </blockquote>
        <p>
         从上面的描述可以看出，MDL子系统显式的对锁类型进行了区分（OBTRUSIVE or UNOBTRUSIVE），存储在数组矩阵m_unobtrusive_lock_increment。 因此对于相容类型的MDL锁类型，例如DML/SELECT，加锁操作几乎没有任何读写锁或MUTEX开销。对应
         <a href="http://dev.mysql.com/worklog/task/?id=7304">
          WL#7304
         </a>
         ,
         <a href="http://dev.mysql.com/worklog/task/?id=7306">
          WL#7306
         </a>
         ， PATCH（
         <a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/7067">
          Rev:7067
         </a>
         ,
         <a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/7129">
          Rev:7129
         </a>
         ）(
         <a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/7586">
          Rev:7586
         </a>
         )
        </p>
        <p>
         <b>
          第三，由于引入了MDL锁，实际上早期版本用于控制Server和引擎层表级并发的THR_LOCK 对于Innodb而言已经有些冗余了，因此Innodb表完全可以忽略这部分的开销。
         </b>
        </p>
        <p>
         不过在已有的逻辑中，Innodb依然依赖THR_LOCK来实现LOCK TABLE tbname READ，因此增加了新的MDL锁类型来代替这种实现。实际上代码的大部分修改都是为了处理新的MDL类型，Innodb的改动只有几行代码。对应
         <a href="http://dev.mysql.com/worklog/task/?id=6671">
          WL#6671
         </a>
         ，PATCH(
         <a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/8232">
          Rev:8232
         </a>
         )
        </p>
        <p>
         <b>
          第四，Server层的用户锁（通过GET_LOCK函数获取）使用MDL来重新实现。
         </b>
        </p>
        <p>
         用户可以通过GET_LOCK()来同时获取多个用户锁，同时由于使用MDL来实现，可以借助MDL子系统实现死锁的检测。注意由于该变化，导致用户锁的命名必须小于64字节，这是受MDL子系统的限制导致。对应
         <a href="http://dev.mysql.com/worklog/task/?id=1159">
          WL#1159
         </a>
         , PATCH(
         <a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/8356">
          Rev:8356
         </a>
         )
        </p>
       </div>
       <hr/>
       <h2>
        MySQL·性能优化·hash_scan 算法的实现解析
       </h2>
       <p>
        <b>
         问题描述
        </b>
       </p>
       <p>
        首先，我们执行下面的TestCase：
       </p>
       <div class="dp-highlighter bg_js">
        <ol class="dp-c" start="1">
         <li class="alt">
          –source include/master-slave.inc
         </li>
         <li class="">
          –source include/have_binlog_format_row.inc
         </li>
         <li class="alt">
          connection slave;
         </li>
         <li class="">
          set global slave_rows_search_algorithms=
          <span class="string">
           ‘TABLE_SCAN’
          </span>
          ;
         </li>
         <li class="alt">
          connection master;
         </li>
         <li class="">
          create table t1(id
          <span class="keyword">
           int
          </span>
          , name varchar(20);
         </li>
         <li class="alt">
          insert into t1 values(1,
          <span class="string">
           ‘a’
          </span>
          );
         </li>
         <li class="">
          insert into t2 values(2,
          <span class="string">
           ‘b’
          </span>
          );
         </li>
         <li class="alt">
          ……
         </li>
         <li class="">
          insert into t3 values(1000,
          <span class="string">
           ‘xxx’
          </span>
          );
         </li>
         <li class="alt">
          <span class="keyword">
           delete
          </span>
          from t1;
         </li>
         <li class="">
          —source include/rpl_end.inc
         </li>
        </ol>
       </div>
       <p>
        随着 t1 数据量的增大，rpl_hash_scan.test 的执行时间会随着 t1 数据量的增大而快速的增长，因为在执行 ‘delete from t1;’ 对于t1的每一行删除操作，备库都要扫描t1,即全表扫描，如果 select count(*) from t1 = N, 则需要扫描Ｎ次 t1 表， 则读取记录数为： O(N + (N-1) + (N-2) + …. + 1) = O(N^2)，在 replication 没有引入 hash_scan，binlog_format=row时，对于无索引表，是通过 table_scan 实现的，如果一个update_rows_log_event/delete_rows_log_event 包含多行修改时，每个修改都要进行全表扫描来实现，其 stack 如下：
       </p>
       <div class="dp-highlighter bg_js">
        <ol class="dp-c" start="1">
         <li class="alt">
          <span class="preprocessor">
           #0 Rows_log_event::do_table_scan_and_update
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           #1 0x0000000000a3d7f7 in Rows_log_event::do_apply_event
          </span>
         </li>
         <li class="alt">
          <span class="preprocessor">
           #2 0x0000000000a28e3a in Log_event::apply_event
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           #3 0x0000000000a8365f in apply_event_and_update_pos
          </span>
         </li>
         <li class="alt">
          <span class="preprocessor">
           #4 0x0000000000a84764 in exec_relay_log_event
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           #5 0x0000000000a89e97 in handle_slave_sql (arg=0x1b3e030)
          </span>
         </li>
         <li class="alt">
          <span class="preprocessor">
           #6 0x0000000000e341c3 in pfs_spawn_thread (arg=0x2b7f48004b20)
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           #7 0x0000003a00a07851 in start_thread () from /lib64/libpthread.so.0
          </span>
         </li>
         <li class="alt">
          <span class="preprocessor">
           #8 0x0000003a006e767d in clone () from /lib64/libc.so.6
          </span>
         </li>
        </ol>
       </div>
       <p>
        这种情况下，往往会造成备库延迟，这也是无索引表所带来的复制延迟问题。
       </p>
       <p>
        如何解决问题：
       </p>
       <ol>
        <li>
         RDS 为了解这个问题，会在每个表创建的时候检查一下表是否包含主建或者唯一建，如果没有包含，则创建一个隐式主建，此主建对用户透明，用户无感，相应的show create, select * 等操作会屏蔽隐式主建，从而可以减少无索引表带来的影响;
        </li>
        <li>
         官方为了解决这个问题，在5.6.6 及以后版本引入参数 slave_rows_search_algorithms ，用于指示备库在 apply_binlog_event时使用的算法，有三种算法TABLE_SCAN,INDEX_SCAN,HASH_SCAN，其中table_scan与index_scan是已经存在的，本文主要研究HASH_SCAN的实现方式，关于参数slave_rows_search_algorithms的设置。
        </li>
       </ol>
       <p>
        <b>
         hash_scan 的实现方法：
        </b>
       </p>
       <p>
        简单的讲，在 apply rows_log_event时，会将 log_event 中对行的更新缓存在两个结构中，分别是：m_hash, m_distinct_key_list。 m_hash：主要用来缓存更新的行记录的起始位置，是一个hash表； m_distinct_key_list：如果有索引，则将索引的值push 到m_distinct_key_list，如果表没有索引，则不使用这个List结构； 其中预扫描整个调用过程如下： Log_event::apply_event
       </p>
       <div class="dp-highlighter bg_js">
        <ol class="dp-c" start="1">
         <li class="alt">
          Rows_log_event::do_apply_event
         </li>
         <li class="">
          Rows_log_event::do_hash_scan_and_update
         </li>
         <li class="alt">
          Rows_log_event::do_hash_row  (add entry info of changed records)
         </li>
         <li class="">
          <span class="keyword">
           if
          </span>
          (m_key_index &lt; MAX_KEY) (index used instead of table scan)
         </li>
         <li class="alt">
          Rows_log_event::add_key_to_distinct_keyset ()
         </li>
        </ol>
       </div>
       <p>
        当一个event 中包含多个行的更改时，会首先扫描所有的更改，将结果缓存到m_hash中，如果该表有索引，则将索引的值缓存至m_distinct_key_list List 中，如果没有，则不使用这个缓存结构，而直接进行全表扫描；
       </p>
       <p>
        <b>
         执行 stack 如下：
        </b>
       </p>
       <div class="dp-highlighter bg_js">
        <ol class="dp-c" start="1">
         <li class="alt">
          <span class="preprocessor">
           #0 handler::ha_delete_row
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           #1 0x0000000000a4192b in Delete_rows_log_event::do_exec_row
          </span>
         </li>
         <li class="alt">
          <span class="preprocessor">
           #2 0x0000000000a3a9c8 in Rows_log_event::do_apply_row
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           #3 0x0000000000a3c1f4 in Rows_log_event::do_scan_and_update
          </span>
         </li>
         <li class="alt">
          <span class="preprocessor">
           #4 0x0000000000a3c5ef in Rows_log_event::do_hash_scan_and_update
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           #5 0x0000000000a3d7f7 in Rows_log_event::do_apply_event
          </span>
         </li>
         <li class="alt">
          <span class="preprocessor">
           #6 0x0000000000a28e3a in Log_event::apply_event
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           #7 0x0000000000a8365f in apply_event_and_update_pos
          </span>
         </li>
         <li class="alt">
          <span class="preprocessor">
           #8 0x0000000000a84764 in exec_relay_log_event
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           #9 0x0000000000a89e97 in handle_slave_sql
          </span>
         </li>
         <li class="alt">
          <span class="preprocessor">
           #10 0x0000000000e341c3 in pfs_spawn_thread
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           #11 0x0000003a00a07851 in start_thread ()
          </span>
         </li>
         <li class="alt">
          <span class="preprocessor">
           #12 0x0000003a006e767d in clone ()
          </span>
         </li>
        </ol>
       </div>
       <p>
        <b>
         执行过程说明：
        </b>
       </p>
       <p>
        Rows_log_event::do_scan_and_update
       </p>
       <div class="dp-highlighter bg_js">
        <ol class="dp-c" start="1">
         <li class="alt">
          open_record_scan()
         </li>
         <li class="">
          <span class="keyword">
           do
          </span>
         </li>
         <li class="alt">
          next_record_scan()
         </li>
         <li class="">
          <span class="keyword">
           if
          </span>
          (m_key_index &gt; MAX_KEY)
         </li>
         <li class="alt">
          ha_rnd_next();
         </li>
         <li class="">
          <span class="keyword">
           else
          </span>
         </li>
         <li class="alt">
          ha_index_read_map(m_key from m_distinct_key_list)
         </li>
         <li class="">
          entry= m_hash-&gt;get()
         </li>
         <li class="alt">
          m_hash-&gt;del(entry);
         </li>
         <li class="">
          do_apply_row()
         </li>
         <li class="alt">
          <span class="keyword">
           while
          </span>
          (m_hash-&gt;size &gt; 0);
         </li>
        </ol>
       </div>
       <p>
        从执行过程上可以看出，当使用hash_scan时，只会全表扫描一次，虽然会多次遍历m_hash这个hash表，但是这个扫描是O(1),所以，代价很小，因此可以降低扫描次数，提高执行效率。
       </p>
       <p>
        <b>
         hash_scan 的一个 bug
        </b>
       </p>
       <blockquote>
        <p>
         bug详情：
         <a href="http://bugs.mysql.com/bug.php?id=72788">
          http://bugs.mysql.com/bug.php?id=72788
          <br/>
         </a>
         bug原因：m_distinct_key_list 中的index key 不是唯一的，所以存在着对已经删除了的记录重复删除的问题。
         <br/>
         bug修复：
         <a href="http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/8494">
          http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/8494
         </a>
        </p>
       </blockquote>
       <p>
        <b>
         问题扩展：
        </b>
       </p>
       <ul>
        <li>
         在没有索引的情况下，是不是把 hash_scan 打开就能提高效率，降低延迟呢？不一定，如果每次更新操作只一条记录，此时仍然需要全表扫描，并且由于entry 的开销，应该会有后退的情况；
        </li>
        <li>
         一个event中能包含多少条记录的更新呢？这个和表结构以及记录的数据大小有关，一个event 的大小不会超过9000 bytes, 没有参数可以控制这个size；
        </li>
        <li>
         hash_scan 有没有限制呢？hash_scan 只会对更新、删除操作有效，对于binlog_format=statement 产生的 Query_log_event 或者binlog_format=row 时产生的 Write_rows_log_event 不起作用；
        </li>
       </ul>
       <div>
        <hr/>
       </div>
       <h2>
        TokuDB·版本优化·7.5.0
       </h2>
       <p>
        TokuDB　7.5.0大版本已发布，是一个里程碑的版本，这里谈几点优化，以飨存储引擎爱好者们。
       </p>
       <p>
        <b>
         a) shutdown加速
        </b>
       </p>
       <p>
        有用户反馈TokuDB在shutdown的时候，半个小时还没完事，非常不可接受。在shutdown的时候，TokuDB在干什么呢？在做checkpoint，把内存中的节点数据序列化并压缩到磁盘。
       </p>
       <p>
        那为什么如此耗时呢？如果tokudb_cache_size开的比较大，内存中的节点会非常多，在shutdown的时候，大家都排队等着被压缩到磁盘（串行的）。
       </p>
       <p>
        在7.5.0版本，TokuDB官方针对此问题进行了优化，使多个节点并行压缩来缩短时间。
       </p>
       <p>
        BTW: TokuDB在早期设计的时候已保留并行接口，只是一直未开启。
       </p>
       <p>
        <b>
         b) 内节点读取加速
        </b>
       </p>
       <p>
        在内存中，TokuDB内节点(internal node)的每个message buffer都有２个重要数据结构：
       </p>
       <blockquote>
        <p>
         1) FIFO结构，保存{key, value}
         <br/>
         2) OMT结构，保存{key, FIFO-offset}
        </p>
       </blockquote>
       <p>
        由于FIFO不具备快速查找特性，就利用OMT来做快速查找(根据key查到value)。这样，当内节点发生cache miss的时候，索引层需要做：
       </p>
       <blockquote>
        <p>
         1) 从磁盘读取节点内容到内存
         <br/>
         2) 构造FIFO结构
         <br/>
         3) 根据FIFO构造OMT结构(做排序)
        </p>
       </blockquote>
       <p>
        由于TokuDB内部有不少性能探(ji)针(shu)，他们发现步骤3)是个不小的性能消耗点，因为每次都要把message buffer做下排序构造出OMT，于是在7.5.0版本，把OMT的FIFO-offset(已排序)也持久化到磁盘，这样排序的损耗就没了。
       </p>
       <p>
        <b>
         c) 顺序写加速
        </b>
       </p>
       <p>
        当写发生的时候，会根据当前的key在pivots里查找(二分)当前写要落入哪个mesage buffer，如果写是顺序(或局部顺序，数据走向为最右边路径)的，就可以避免由＂查找＂带来的额外开销。
       </p>
       <p>
        <img src="http://dataunion.org/wp-content/uploads/2015/01/54be0f35dd41d_middle.jpg"/>
       </p>
       <p>
       </p>
       <p>
        如何判断是顺序写呢？TokuDB使用了一种简单的启发式方法(heurstic)：seqinsert_score积分式。如果：
       </p>
       <blockquote>
        <p>
         1) 当前写入落入最右节点，对seqinsert_score加一分(原子)
         <br/>
         2) 当前写入落入非最右节点，对seqinsert_score清零(原子)
        </p>
       </blockquote>
       <p>
        当seqinsert_score大于100的时候，就可以认为是顺序写，当下次写操作发生时，首先与最右的节点pivot进行对比判断，如果确实为顺序写，则会被写到该节点，省去不少compare开销。方法简单而有效。
       </p>
       <hr/>
       <h2>
        MariaDB·　性能优化·filesort with small LIMIT optimization
       </h2>
       <p>
        从MySQL 5.6.2/MariaDB 10.0.0版本开始，MySQL/MariaDB针对”ORDER BY …LIMIT n”语句实现了一种新的优化策略。当n足够小的时候，优化器会采用一个容积为n的优先队列来进行排序，而不是排序所有数据然后取出前n条。 这个新算法可以这么描述：（假设是ASC排序）
       </p>
       <ol>
        <li>
         建立一个只有n个元素的优先队列（堆），根节点为堆中最大元素
        </li>
        <li>
         根据其他条件，依次从表中取出一行数据
        </li>
        <li>
         如果当前行的排序关键字小于堆头，则把当前元素替换堆头，重新Shift保持堆的特性
        </li>
        <li>
         再取一条数据重复2步骤，如果没有下一条数据则执行5
        </li>
        <li>
         依次取出堆中的元素（从大到小排序），逆序输出（从小到大排序），即可得ASC的排序结果
        </li>
       </ol>
       <p>
        这样的算法，时间复杂度为m*log(n)，m为索引过滤后的行数，n为LIMIT的行数。而原始的全排序算法，时间复杂度为m*log(m)。只要n远小于m，这个算法就会很有效。
       </p>
       <p>
        不过在MySQL 5.6中，除了optimizer_trace，没有好的方法来看到这个新的执行计划到底起了多少作用。MariaDB 10.013开始，提供一个系统状态，可以查看新执行计划调用的次数：
       </p>
       <blockquote>
        <p>
         Sort_priority_queue_sorts
         <br/>
         描述: 通过优先队列实现排序的次数。(总排序次数=Sort_range+Sort_scan)
         <br/>
         范围: Global, Session
         <br/>
         数据类型: numeric
         <br/>
         引入版本: MariaDB 10.0.13
        </p>
       </blockquote>
       <p>
        此外，MariaDB还将此信息打入了Slow Log中。只要指定 log_slow_verbosity=query_plan，就可以在Slow Log中看到这样的记录：
       </p>
       <div class="dp-highlighter bg_js">
        <ol class="dp-c" start="1">
         <li class="alt">
          <span class="preprocessor">
           # Time: 140714 18:30:39
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           # User@Host: root[root] @ localhost []
          </span>
         </li>
         <li class="alt">
          <span class="preprocessor">
           # Thread_id: 3  Schema: test  QC_hit: No
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           # Query_time: 0.053857  Lock_time: 0.000188  Rows_sent: 11  Rows_examined: 100011
          </span>
         </li>
         <li class="alt">
          <span class="preprocessor">
           # Full_scan: Yes  Full_join: No  Tmp_table: No  Tmp_table_on_disk: No
          </span>
         </li>
         <li class="">
          <span class="preprocessor">
           # Filesort: Yes  Filesort_on_disk: No  Merge_passes: 0  Priority_queue: Yes
          </span>
         </li>
         <li class="alt">
          SET timestamp=1405348239;SET timestamp=1405348239;
         </li>
         <li class="">
          select * from t1 where col1 between 10 and 20 order by col2 limit 100;
         </li>
        </ol>
       </div>
       <p>
        “Priority_queue: Yes” 就表示这个Query利用了优先队列的执行计划(pt-query-digest 目前已经可以解析 Priority_queue 这个列)。更多精彩内容，敬请期待！
       </p>
       <p>
       </p>
       <div>
        感谢淘宝数据库项目组丁奇、鸣嵩、彭立勋、皓庭、项仲、剑川、武藏、祁奚、褚霸、一工。审校：刘亚琼
        <p>
        </p>
        <div>
         文章出处：
         <a href="http://dataunion.org/MySQL.taobao.org">
          MySQL.taobao.org
         </a>
        </div>
       </div>
      </div>
      <div>
       <strong>
        注：转载文章均来自于公开网络，仅供学习使用，不会用于任何商业用途，如果侵犯到原作者的权益，请您与我们联系删除或者授权事宜，联系邮箱：contact@dataunion.org。转载数盟网站文章请注明原文章作者，否则产生的任何版权纠纷与数盟无关。
       </strong>
      </div>
      <!--content_text-->
      <div class="fenxian">
       <!-- JiaThis Button BEGIN -->
       <div class="jiathis_style_32x32">
        <p class="jiathis_button_weixin">
        </p>
        <p class="jiathis_button_tsina">
        </p>
        <p class="jiathis_button_qzone">
        </p>
        <p class="jiathis_button_cqq">
        </p>
        <p class="jiathis_button_tumblr">
        </p>
        <a class="jiathis jiathis_txt jtico jtico_jiathis" href="http://www.jiathis.com/share" target="_blank">
        </a>
        <p class="jiathis_counter_style">
        </p>
       </div>
       <!-- JiaThis Button END -->
      </div>
     </article>
     <!--content-->
     <!--相关文章-->
     <div class="xianguan">
      <div class="xianguantitle">
       相关文章！
      </div>
      <ul class="pic">
       <li>
        <a href="http://dataunion.org/20517.html">
         <img src="http://dataunion.org/wp-content/uploads/2015/07/t012366e61c52d9046b-300x228.png"/>
        </a>
        <a class="link" href="http://dataunion.org/20517.html" rel="bookmark" title="MySQL索引背后的数据结构及算法原理">
         MySQL索引背后的数据结构及算法原理
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/20229.html">
         <img src="http://dataunion.org/wp-content/uploads/2015/07/t012366e61c52d9046b-300x228.png"/>
        </a>
        <a class="link" href="http://dataunion.org/20229.html" rel="bookmark" title="8 个不得不说的 MySQL 陷阱">
         8 个不得不说的 MySQL 陷阱
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/20094.html">
         <img src="http://dataunion.org/wp-content/uploads/2015/07/t012366e61c52d9046b-300x228.png"/>
        </a>
        <a class="link" href="http://dataunion.org/20094.html" rel="bookmark" title="老叶观点：MySQL开发规范之我见">
         老叶观点：MySQL开发规范之我见
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/19973.html">
         <img src="http://dataunion.org/wp-content/uploads/2015/06/u1068384158883784220fm21gp0.jpg"/>
        </a>
        <a class="link" href="http://dataunion.org/19973.html" rel="bookmark" title="MySQL 调优/优化的 100 个建议">
         MySQL 调优/优化的 100 个建议
        </a>
       </li>
      </ul>
     </div>
     <!--相关文章-->
     <div class="comment" id="comments">
      <!-- You can start editing here. -->
      <!-- If comments are open, but there are no comments. -->
      <div class="title">
       期待你一针见血的评论，Come on！
      </div>
      <div id="respond">
       <p>
        不用想啦，马上
        <a href="http://dataunion.org/wp-login.php?redirect_to=http%3A%2F%2Fdataunion.org%2F8791.html">
         "登录"
        </a>
        发表自已的想法.
       </p>
      </div>
     </div>
     <!-- .nav-single -->
    </div>
    <!--Container End-->
    <aside id="sitebar">
     <div class="sitebar_list2">
      <div class="wptag">
       <span class="tagtitle">
        热门标签+
       </span>
       <div class="tagg">
        <ul class="menu" id="menu-%e5%8f%8b%e6%83%85%e9%93%be%e6%8e%a5">
         <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-1605" id="menu-item-1605">
          <a href="http://taidizh.com/">
           泰迪智慧
          </a>
         </li>
         <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-20884" id="menu-item-20884">
          <a href="http://www.transwarp.cn/">
           星环科技
          </a>
         </li>
         <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-3538" id="menu-item-3538">
          <a href="http://datall.org/">
           珈和遥感
          </a>
         </li>
         <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-20888" id="menu-item-20888">
          <a href="http://www.chinahadoop.cn/">
           小象学院
          </a>
         </li>
        </ul>
       </div>
      </div>
     </div>
     <div class="sitebar_list">
      <div class="textwidget">
       <div align="center">
        <a href="http://study.163.com/course/courseMain.htm?courseId=991022" target="_blank">
         <img src="http://dataunion.org/wp-content/uploads/2016/03/dv.jpg"/>
        </a>
       </div>
      </div>
     </div>
     <div class="sitebar_list">
      <h4 class="sitebar_title">
       文章分类
      </h4>
      <div class="tagcloud">
       <a class="tag-link-44" href="http://dataunion.org/category/industry/demo" style="font-size: 10.204724409449pt;" title="4个话题">
        Demo展示
       </a>
       <a class="tag-link-31" href="http://dataunion.org/category/experts" style="font-size: 15.826771653543pt;" title="52个话题">
        专家团队
       </a>
       <a class="tag-link-870" href="http://dataunion.org/category/tech/ai" style="font-size: 19.795275590551pt;" title="273个话题">
        人工智能
       </a>
       <a class="tag-link-488" href="http://dataunion.org/category/%e5%8a%a0%e5%85%a5%e6%95%b0%e7%9b%9f" style="font-size: 8pt;" title="1个话题">
        加入数盟
       </a>
       <a class="tag-link-869" href="http://dataunion.org/category/tech/viz" style="font-size: 17.204724409449pt;" title="93个话题">
        可视化
       </a>
       <a class="tag-link-30" href="http://dataunion.org/category/partners" style="font-size: 10.645669291339pt;" title="5个话题">
        合作伙伴
       </a>
       <a class="tag-link-889" href="http://dataunion.org/category/parterc" style="font-size: 11.582677165354pt;" title="8个话题">
        合作会议
       </a>
       <a class="tag-link-104" href="http://dataunion.org/category/books" style="font-size: 12.96062992126pt;" title="15个话题">
        图书
       </a>
       <a class="tag-link-220" href="http://dataunion.org/category/tech/base" style="font-size: 19.850393700787pt;" title="281个话题">
        基础架构
       </a>
       <a class="tag-link-219" href="http://dataunion.org/category/tech/analysis" style="font-size: 19.409448818898pt;" title="232个话题">
        数据分析
       </a>
       <a class="tag-link-887" href="http://dataunion.org/category/tech/dm" style="font-size: 13.291338582677pt;" title="17个话题">
        数据挖掘
       </a>
       <a class="tag-link-34" href="http://dataunion.org/category/tech" style="font-size: 20.732283464567pt;" title="404个话题">
        文章
       </a>
       <a class="tag-link-1" href="http://dataunion.org/category/uncategorized" style="font-size: 22pt;" title="693个话题">
        未分类
       </a>
       <a class="tag-link-4" href="http://dataunion.org/category/events" style="font-size: 14.503937007874pt;" title="29个话题">
        活动
       </a>
       <a class="tag-link-890" href="http://dataunion.org/category/tech/%e6%b7%b1%e5%ba%a6%e5%ad%a6%e4%b9%a0" style="font-size: 10.204724409449pt;" title="4个话题">
        深度学习
       </a>
       <a class="tag-link-221" href="http://dataunion.org/category/tech/devl" style="font-size: 18.968503937008pt;" title="193个话题">
        编程语言
       </a>
       <a class="tag-link-888" href="http://dataunion.org/category/career" style="font-size: 15.661417322835pt;" title="48个话题">
        职业规划
       </a>
       <a class="tag-link-5" href="http://dataunion.org/category/jobs" style="font-size: 14.11811023622pt;" title="25个话题">
        职位
       </a>
       <a class="tag-link-871" href="http://dataunion.org/category/industry" style="font-size: 15.716535433071pt;" title="49个话题">
        行业
       </a>
       <a class="tag-link-613" href="http://dataunion.org/category/industry/case" style="font-size: 16.984251968504pt;" title="84个话题">
        行业应用
       </a>
       <a class="tag-link-885" href="http://dataunion.org/category/industry/news" style="font-size: 17.425196850394pt;" title="102个话题">
        行业资讯
       </a>
       <a class="tag-link-10" href="http://dataunion.org/category/training" style="font-size: 14.228346456693pt;" title="26个话题">
        课程
       </a>
       <a class="tag-link-16" href="http://dataunion.org/category/sources" style="font-size: 15.661417322835pt;" title="48个话题">
        资源
       </a>
      </div>
     </div>
     <div class="sitebar_list">
      <h4 class="sitebar_title">
       功能
      </h4>
      <ul>
       <li>
        <a href="http://dataunion.org/wp-login.php?action=register">
         注册
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/wp-login.php">
         登录
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/feed">
         文章
         <abbr title="Really Simple Syndication">
          RSS
         </abbr>
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/comments/feed">
         评论
         <abbr title="Really Simple Syndication">
          RSS
         </abbr>
        </a>
       </li>
       <li>
        <a href="https://cn.wordpress.org/" title="基于WordPress，一个优美、先进的个人信息发布平台。">
         WordPress.org
        </a>
       </li>
      </ul>
     </div>
    </aside>
    <div class="clear">
    </div>
   </div>
   <!--main-->
   ﻿
   <footer id="dibu">
    <div class="about">
     <div class="right">
      <ul class="menu" id="menu-%e5%ba%95%e9%83%a8%e8%8f%9c%e5%8d%95">
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-18024" id="menu-item-18024">
        <a href="http://dataunion.org/category/partners">
         合作伙伴
        </a>
       </li>
       <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-20881" id="menu-item-20881">
        <a href="http://dataunion.org/contribute">
         文章投稿
        </a>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-20872" id="menu-item-20872">
        <a href="http://dataunion.org/category/%e5%8a%a0%e5%85%a5%e6%95%b0%e7%9b%9f">
         加入数盟
        </a>
       </li>
       <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-22441" id="menu-item-22441">
        <a href="http://dataunion.org/f-links">
         友情链接
        </a>
       </li>
       <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-20874" id="menu-item-20874">
        <a href="http://dataunion.org/aboutus">
         关于数盟
        </a>
       </li>
      </ul>
      <p class="banquan">
       数盟社区        ，
        做最棒的数据科学社区
      </p>
     </div>
     <div class="left">
      <ul class="bottomlist">
       <li>
        <a href="http://weibo.com/DataScientistUnion  " target="_blank" 　title="">
         <img src="http://dataunion.org/wp-content/themes/yzipi/images/weibo.png"/>
        </a>
       </li>
       <li>
        <a class="cd-popup-trigger" href="http://dataunion.org/8791.html#0">
         <img src="http://dataunion.org/wp-content/themes/yzipi/images/weixin.png"/>
        </a>
       </li>
      </ul>
      <div class="cd-popup">
       <div class="cd-popup-container">
        <h1>
         扫描二维码,加微信公众号
        </h1>
        <img src="http://dataunion.org/wp-content/themes/yzipi/images/2014-12-06-1515289049.png"/>
        <a class="cd-popup-close" href="http://dataunion.org/8791.html">
        </a>
       </div>
       <!-- cd-popup-container -->
      </div>
      <!-- cd-popup -->
     </div>
    </div>
    <!--about-->
    <div class="bottom">
     <a href="http://dataunion.org/">
      数盟社区
     </a>
     <a href="http://www.miitbeian.gov.cn/" rel="external nofollow" target="_blank">
      京ICP备14026740号
     </a>
     联系我们：
     <a href="mailto:contact@dataunion.org" target="_blank">
      contact@dataunion.org
     </a>
     <div class="tongji">
     </div>
     <!--bottom-->
     <div class="scroll" id="scroll" style="display:none;">
      ︿
     </div>
    </div>
   </footer>
   <!--dibu-->
  </div>
 </body>
</html>